package com.lianzai.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by IBM on 2018/10/30.
 */
@Slf4j
public class WxUtil {

    /**
     * 获取AccessToken失败
     * @param appId
     * @param appsecret
     * @return
     */
    public static JSONObject getPublicAccessToken(String appId, String appsecret){
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential")
                    .append("&appid=").append(appId)
                    .append("&secret=").append(appsecret);

            JSONObject json = httpsRequest(sb.toString(), "GET", null);
            if(json==null || (json.containsKey("errcode") && !"0".equals(json.getString("errcode")))){
                log.error("获取AccessToken失败"); return null;
            }

            return json;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建菜单
     * @param jsonData
     * @param accessToken
     * @return
     */
    public static JSONObject createMenu(String jsonData, String accessToken){
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("https://api.weixin.qq.com/cgi-bin/menu/create?")
                    .append("access_token=").append(accessToken);

            JSONObject json = httpsRequest(sb.toString(), "POST", jsonData);
            if(json==null || (json.containsKey("errcode")  && !"0".equals(json.getString("errcode")))){
                log.error("创建菜单失败"); return null;
            }

            return json;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取微信openId
     * @return
     */
    public static JSONObject getOpenIdByJsCode(String code, String appid, String appSecret){
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("https://api.weixin.qq.com/sns/oauth2/access_token?")
                    .append("appid=").append(appid)
                    .append("&secret=").append(appSecret)
                    .append("&code=").append(code)
                    .append("&grant_type=authorization_code");

            JSONObject json = httpsRequest(sb.toString(), "GET", null);
            if(json==null || (json.containsKey("errcode")  && !"0".equals(json.getString("errcode")))){
                log.error("获取openId失败"); return null;
            }

            return json;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取微信openId
     * @return
     */
    public static JSONObject getOpenIdForApplet(String code, String appid, String appSecret){
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("https://api.weixin.qq.com/sns/jscode2session?")
                    .append("appid=").append(appid)
                    .append("&secret=").append(appSecret)
                    .append("&js_code=").append(code)
                    .append("&grant_type=authorization_code");

            JSONObject json = httpsRequest(sb.toString(), "GET", null);
            if(json==null || (json.containsKey("errcode")  && !"0".equals(json.getString("errcode")))){
                log.error("获取openId失败"); return null;
            }

            return json;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成网页授权 URL (第三方平台开发)
     *
     * @param appid           appid
     * @param redirect_uri    自动URLEncoder
     * @return url
     */
    public static String connectOauth2Authorize(
            String appid,
            String redirect_uri) {
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("https://open.weixin.qq.com/connect/oauth2/authorize?")
                    .append("appid=")
                    .append(appid)
                    .append("&redirect_uri=")
                    .append(URLEncoder.encode(redirect_uri, "utf-8"))
                    .append("&response_type=code&scope=snsapi_base&state=1#wechat_redirect");

            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 解析xml数据
     * @param request
     * @return
     * @throws Exception
     */
    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();

        // 遍历所有子节点
        for (Element e : elementList){
            map.put(e.getName(), e.getText());
        }

        // 释放资源
        inputStream.close();
        return map;
    }

    /**
     * 微信推送校验
     * @param wxAttToken
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static Boolean checkWxPushSignature(String wxAttToken, String signature, String timestamp, String nonce){
        try {
            String[] arr = new String[] { wxAttToken, timestamp, nonce };
            Arrays.sort(arr);
            StringBuilder content = new StringBuilder();
            for (int i = 0; i < arr.length; i++) content.append(arr[i]);
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());
            String tmpStr = byteToStr(digest);
            return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
        } catch (Exception e){
            log.error("微信推送校验异常：{}", e.getMessage());
            e.printStackTrace();
        }
        return false;
    }

    public static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    public static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }

    /**
     * 发送http请求
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            TrustManager[] tm = { new WxX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn =  (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod)){
                httpUrlConn.connect();
            }

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            httpUrlConn.disconnect();

            jsonObject = JSON.parseObject(buffer.toString());
        }  catch (Exception e) {
            log.error("http请求发送失败：{}", e.getMessage());
            e.printStackTrace();
        }
        return jsonObject;
    }
}
